﻿using SqlSugar;

namespace SimpleX
{
    internal class SqlSugarCodeFirst
    {
        public static void Execute()
        {
            //遍历配置
            DbContext.DbConfigs.ForEach(it =>
            {
                //是否需要初始化数据库
                if (it.IsInitDb)
                {
                    InitDb(it);//初始化数据库表结构
                }

                if (it.IsSeedData)
                {
                    InitSeedData(it);//初始化基本信息
                }
            });
        }

        private static void InitSeedData(SqlSugarConfig config)
        {
            var entityTypes = App.EffectiveTypes.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass && u.IsDefined(typeof(SugarTable), false));
            if (!entityTypes.Any()) return;//没有就退出

            var db = DbContext.Db.GetConnectionScope(config.ConfigId);//获取数据库对象
                                                                      // 获取所有种子配置-初始化数据
            var seedDataTypes = App.EffectiveTypes.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass
                && u.GetInterfaces().Any(i => i.HasImplementedRawGeneric(typeof(ISqlSugarEntitySeedData<>))));
            if (!seedDataTypes.Any()) return;
            foreach (var seedType in seedDataTypes)//遍历种子类
            {
                //使用与指定参数匹配程度最高的构造函数来创建指定类型的实例。
                var instance = Activator.CreateInstance(seedType);
                //获取SeedData方法
                var hasDataMethod = seedType.GetMethod("SeedData");
                //判断是否有种子数据
                var seedData = ((IEnumerable)hasDataMethod?.Invoke(instance, null))?.Cast<object>();
                if (seedData == null) continue;//没有种子数据就下一个
                var entityType = seedType.GetInterfaces().First().GetGenericArguments().First();//获取实体类型
                var tenantAtt = entityType.GetCustomAttribute<TenantAttribute>();//获取sqlsugar租户特性
                if (tenantAtt != null && tenantAtt.configId.ToString() != config.ConfigId.ToString()) continue;//如果不是当前租户的就下一个
                var seedDataTable = seedData.ToList().ToDataTable();//获取种子数据
                seedDataTable.TableName = db.EntityMaintenance.GetEntityInfo(entityType).DbTableName;//获取表名
                if (config.IsUnderLine) // 驼峰转下划线
                {
                    foreach (DataColumn col in seedDataTable.Columns)
                    {
                        col.ColumnName = UtilMethods.ToUnderLine(col.ColumnName);
                    }
                }
                if (seedDataTable.Columns.Contains(SqlsugarConst.DB_PrimaryKey))//判断种子数据是否有主键
                {
                    var storage = db.Storageable(seedDataTable).WhereColumns(SqlsugarConst.DB_PrimaryKey).ToStorage();

                    //codefirst暂时全部新增,根据主键更新,用户表暂不更新
                    storage.AsInsertable.ExecuteCommand();

                    var ignoreUpdate = hasDataMethod.GetCustomAttribute<IgnoreSeedDataUpdateAttribute>();//读取忽略更新特性
                    if (ignoreUpdate == null)
                        storage.AsUpdateable.ExecuteCommand();//只有没有忽略更新的特性才执行更新
                }
                else // 没有主键或者不是预定义的主键(有重复的可能)
                {
                    //全量插入
                    var storage = db.Storageable(seedDataTable).ToStorage();
                    storage.AsInsertable.ExecuteCommand();
                }
            }
        }

        /// <summary>
        /// 初始化数据库表结构
        /// </summary>
        /// <param name="config">数据库配置</param>
        private static void InitDb(SqlSugarConfig config)
        {
            try
            {
                var connection = DbContext.Db.GetConnection(config.ConfigId);
                connection.DbMaintenance.CreateDatabase();//创建数据库
            }
            catch (Exception ex)
            {
                Console.WriteLine($"创建数据库失败,开始尝试操作表! ex:{ex.Message}");
            }

            var entityTypes = App.EffectiveTypes.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass && u.IsDefined(typeof(SugarTable), false));
            if (!entityTypes.Any()) return;//没有就退出
            var db = DbContext.Db.GetConnectionScope(config.ConfigId);//获取数据库对象

            db.Aop.OnLogExecuting = (x, p) =>
            {
                if (x.Contains("AuditFlag"))
                {
                    Console.WriteLine(x);
                    Console.WriteLine(p.FirstOrDefault()?.Value);
                }
            };

            foreach (var entityType in entityTypes)
            {
                var tenantAtt = entityType.GetCustomAttribute<TenantAttribute>();//获取Sqlsugar多租户特性
                var ignoreInit = entityType.GetCustomAttribute<IgnoreInitTableAttribute>();//获取忽略初始化特性
                if (ignoreInit != null) continue;//如果有忽略初始化特性
                if (tenantAtt != null && tenantAtt.configId.ToString() != config.ConfigId.ToString()) continue;//如果特性存在并且租户ID不是当前数据库ID
                var splitTable = entityType.GetCustomAttribute<SplitTableAttribute>();//获取自动分表特性

                if (splitTable == null)//如果特性是空
                    db.CodeFirst.InitTables(entityType);//普通创建
                else
                    db.CodeFirst.SplitTables().InitTables(entityType);//自动分表创建
            }
        }
    }
}